/*
===========================================================================

Wolfenstein: Enemy Territory GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. 

This file is part of the Wolfenstein: Enemy Territory GPL Source Code (Wolf ET Source Code).  

Wolf ET Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Wolf ET Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Wolf ET Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Wolf: ET Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Wolf ET Source Code.  If not, please request a copy in writing from id Software at the address below.

If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.

===========================================================================
*/

//-----------------------------------------------------------------------------
//
//  $Logfile:: /Wolf4/src/bspc/map_sin.c                                      $
// $Revision: 1.5 $
//   $Author: lordhavoc $
//     $Date: 2009-02-11 15:21:07 -0600 (Wed, 11 Feb 2009) $

#include "qbsp.h"
#include "l_bsp_sin.h"
#include "aas_map.h"         //AAS_CreateMapBrushes


//====================================================================


/*
===========
Sin_BrushContents
===========
*/

int Sin_BrushContents( mapbrush_t *b ) {
	int contents;
	side_t      *s;
	int i;
#ifdef SIN
	float trans = 0;
#else
	int trans;
#endif

	s = &b->original_sides[0];
	contents = s->contents;

#ifdef SIN
	trans = sin_texinfo[s->texinfo].translucence;
#else
	trans = texinfo[s->texinfo].flags;
#endif
	for ( i = 1 ; i < b->numsides ; i++, s++ )
	{
		s = &b->original_sides[i];
#ifdef SIN
		trans += sin_texinfo[s->texinfo].translucence;
#else
		trans |= texinfo[s->texinfo].flags;
#endif
		if ( s->contents != contents ) {
#ifdef SIN
			if (
				( s->contents & CONTENTS_DETAIL && !( contents & CONTENTS_DETAIL ) ) ||
				( !( s->contents & CONTENTS_DETAIL ) && contents & CONTENTS_DETAIL )
				) {
				s->contents |= CONTENTS_DETAIL;
				contents |= CONTENTS_DETAIL;
				continue;
			}
#endif
			printf( "Entity %i, Brush %i: mixed face contents\n"
					, b->entitynum, b->brushnum );
			break;
		}
	}


#ifdef SIN
	if ( contents & CONTENTS_FENCE ) {
//		contents |= CONTENTS_TRANSLUCENT;
		contents |= CONTENTS_DETAIL;
		contents |= CONTENTS_DUMMYFENCE;
		contents &= ~CONTENTS_SOLID;
		contents &= ~CONTENTS_FENCE;
		contents |= CONTENTS_WINDOW;
	}
#endif

	// if any side is translucent, mark the contents
	// and change solid to window
#ifdef SIN
	if ( trans > 0 )
#else
	if ( trans & ( SURF_TRANS33 | SURF_TRANS66 ) )
#endif
	{
		contents |= CONTENTS_Q2TRANSLUCENT;
		if ( contents & CONTENTS_SOLID ) {
			contents &= ~CONTENTS_SOLID;
			contents |= CONTENTS_WINDOW;
		}
	}

	return contents;
} //*/


//============================================================================



/*
=================
ParseBrush
=================
* /
void ParseBrush (entity_t *mapent)
{
	mapbrush_t		*b;
	int			i,j, k;
	int			mt;
	side_t		*side, *s2;
	int			planenum;
	brush_texture_t	td;
#ifdef SIN
   textureref_t newref;
#endif
	int			planepts[3][3];

	if (nummapbrushes == MAX_MAP_BRUSHES)
		Error ("nummapbrushes == MAX_MAP_BRUSHES");

	b = &mapbrushes[nummapbrushes];
	b->original_sides = &brushsides[nummapbrushsides];
	b->entitynum = num_entities-1;
	b->brushnum = nummapbrushes - mapent->firstbrush;

	do
	{
		if (!GetToken (true))
			break;
		if (!strcmp (token, "}") )
			break;

		if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
			Error ("MAX_MAP_BRUSHSIDES");
		side = &brushsides[nummapbrushsides];

		// read the three point plane definition
		for (i=0 ; i<3 ; i++)
		{
			if (i != 0)
				GetToken (true);
			if (strcmp (token, "(") )
				Error ("parsing brush");

			for (j=0 ; j<3 ; j++)
			{
				GetToken (false);
				planepts[i][j] = atoi(token);
			}

			GetToken (false);
			if (strcmp (token, ")") )
				Error ("parsing brush");

		}


		//
		// read the texturedef
		//
		GetToken (false);
		strcpy (td.name, token);

		GetToken (false);
		td.shift[0] = atoi(token);
		GetToken (false);
		td.shift[1] = atoi(token);
		GetToken (false);
#ifdef SIN
		td.rotate = atof(token);
#else
		td.rotate = atoi(token);
#endif
		GetToken (false);
		td.scale[0] = atof(token);
		GetToken (false);
		td.scale[1] = atof(token);

		// find default flags and values
		mt = FindMiptex (td.name);
#ifdef SIN
	  // clear out the masks on newref
	  memset(&newref,0,sizeof(newref));
	  // copy over the name
	  strcpy( newref.name, td.name );

	  ParseSurfaceInfo( &newref );
	  MergeRefs( &bsp_textureref[mt], &newref, &td.tref );
	  side->contents = td.tref.contents;
	  side->surf = td.tref.flags;
#else
		td.flags = textureref[mt].flags;
		td.value = textureref[mt].value;
		side->contents = textureref[mt].contents;
		side->surf = td.flags = textureref[mt].flags;

		if (TokenAvailable())
		{
			GetToken (false);
			side->contents = atoi(token);
			GetToken (false);
			side->surf = td.flags = atoi(token);
			GetToken (false);
			td.value = atoi(token);
		}
#endif

		// translucent objects are automatically classified as detail
#ifdef SIN
		if ( td.tref.translucence > 0 )
#else
		if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
#endif
			side->contents |= CONTENTS_DETAIL;
		if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
			side->contents |= CONTENTS_DETAIL;
		if (fulldetail)
			side->contents &= ~CONTENTS_DETAIL;
		if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1)
			| CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST)  ) )
			side->contents |= CONTENTS_SOLID;

		// hints and skips are never detail, and have no content
		if (side->surf & (SURF_HINT|SURF_SKIP) )
		{
			side->contents = 0;
#ifndef SIN // I think this is a bug of some kind
			side->surf &= ~CONTENTS_DETAIL;
#endif
		}

		//
		// find the plane number
		//
		planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
		if (planenum == -1)
		{
			printf ("Entity %i, Brush %i: plane with no normal\n"
				, b->entitynum, b->brushnum);
			continue;
		}

		//
		// see if the plane has been used already
		//
		for (k=0 ; k<b->numsides ; k++)
		{
			s2 = b->original_sides + k;
			if (s2->planenum == planenum)
			{
				printf ("Entity %i, Brush %i: duplicate plane\n"
					, b->entitynum, b->brushnum);
				break;
			}
			if ( s2->planenum == (planenum^1) )
			{
				printf ("Entity %i, Brush %i: mirrored plane\n"
					, b->entitynum, b->brushnum);
				break;
			}
		}
		if (k != b->numsides)
			continue;		// duplicated

		//
		// keep this side
		//

		side = b->original_sides + b->numsides;
		side->planenum = planenum;
#ifdef SIN
		side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
			&td, vec3_origin, &newref);
	  //
	  // save off lightinfo
	  //
		side->lightinfo = LightinfoForBrushTexture ( &td );
#else
		side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
			&td, vec3_origin);

#endif

		// save the td off in case there is an origin brush and we
		// have to recalculate the texinfo
		side_brushtextures[nummapbrushsides] = td;
#ifdef SIN
	  // save off the merged tref for animating textures
		side_newrefs[nummapbrushsides] = newref;
#endif

		nummapbrushsides++;
		b->numsides++;
	} while (1);

	// get the content for the entire brush
	b->contents = Sin_BrushContents (b);

	// allow detail brushes to be removed
	if (nodetail && (b->contents & CONTENTS_DETAIL) )
	{
		b->numsides = 0;
		return;
	}

	// allow water brushes to be removed
	if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
	{
		b->numsides = 0;
		return;
	}

	// create windings for sides and bounds for brush
	MakeBrushWindings (b);

	// brushes that will not be visible at all will never be
	// used as bsp splitters
	if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
	{
		c_clipbrushes++;
		for (i=0 ; i<b->numsides ; i++)
			b->original_sides[i].texinfo = TEXINFO_NODE;
	}

	//
	// origin brushes are removed, but they set
	// the rotation origin for the rest of the brushes
	// in the entity.  After the entire entity is parsed,
	// the planenums and texinfos will be adjusted for
	// the origin brush
	//
	if (b->contents & CONTENTS_ORIGIN)
	{
		char	string[32];
		vec3_t	origin;

		if (num_entities == 1)
		{
			Error ("Entity %i, Brush %i: origin brushes not allowed in world"
				, b->entitynum, b->brushnum);
			return;
		}

		VectorAdd (b->mins, b->maxs, origin);
		VectorScale (origin, 0.5, origin);

		sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
		SetKeyValue (&entities[b->entitynum], "origin", string);

		VectorCopy (origin, entities[b->entitynum].origin);

		// don't keep this brush
		b->numsides = 0;

		return;
	}

	AddBrushBevels (b);

	nummapbrushes++;
	mapent->numbrushes++;
} //*/

/*
================
MoveBrushesToWorld

Takes all of the brushes from the current entity and
adds them to the world's brush list.

Used by func_group and func_areaportal
================
* /
void MoveBrushesToWorld (entity_t *mapent)
{
	int			newbrushes;
	int			worldbrushes;
	mapbrush_t	*temp;
	int			i;

	// this is pretty gross, because the brushes are expected to be
	// in linear order for each entity

	newbrushes = mapent->numbrushes;
	worldbrushes = entities[0].numbrushes;

	temp = malloc(newbrushes*sizeof(mapbrush_t));
	memcpy (temp, mapbrushes + mapent->firstbrush, newbrushes*sizeof(mapbrush_t));

#if	0		// let them keep their original brush numbers
	for (i=0 ; i<newbrushes ; i++)
		temp[i].entitynum = 0;
#endif

	// make space to move the brushes (overlapped copy)
	memmove (mapbrushes + worldbrushes + newbrushes,
		mapbrushes + worldbrushes,
		sizeof(mapbrush_t) * (nummapbrushes - worldbrushes - newbrushes) );

	// copy the new brushes down
	memcpy (mapbrushes + worldbrushes, temp, sizeof(mapbrush_t) * newbrushes);

	// fix up indexes
	entities[0].numbrushes += newbrushes;
	for (i=1 ; i<num_entities ; i++)
		entities[i].firstbrush += newbrushes;
	free (temp);

	mapent->numbrushes = 0;
} //*/

/*
================
ParseMapEntity
================
* /
qboolean	Sin_ParseMapEntity (void)
{
	entity_t	*mapent;
	epair_t		*e;
	side_t		*s;
	int			i, j;
	int			startbrush, startsides;
	vec_t		newdist;
	mapbrush_t	*b;

	if (!GetToken (true))
		return false;

	if (strcmp (token, "{") )
		Error ("ParseEntity: { not found");

	if (num_entities == MAX_MAP_ENTITIES)
		Error ("num_entities == MAX_MAP_ENTITIES");

	startbrush = nummapbrushes;
	startsides = nummapbrushsides;

	mapent = &entities[num_entities];
	num_entities++;
	memset (mapent, 0, sizeof(*mapent));
	mapent->firstbrush = nummapbrushes;
	mapent->numbrushes = 0;
//	mapent->portalareas[0] = -1;
//	mapent->portalareas[1] = -1;

	do
	{
		if (!GetToken (true))
			Error ("ParseEntity: EOF without closing brace");
		if (!strcmp (token, "}") )
			break;
		if (!strcmp (token, "{") )
			ParseBrush (mapent);
		else
		{
			e = ParseEpair ();
#ifdef SIN
		 //HACK HACK HACK
		 // MED Gotta do this here
		 if ( !stricmp(e->key, "surfacefile") )
			{
			if (!surfacefile[0])
			   {
			   strcpy( surfacefile, e->value );
			   }
			  printf ("--- ParseSurfaceFile ---\n");
			  printf ("Surface script: %s\n", surfacefile);
			  if (!ParseSurfaceFile(surfacefile))
			   {
				 Error ("Script file not found: %s\n", surfacefile);
			   }
			}
#endif
			e->next = mapent->epairs;
			mapent->epairs = e;
		}
	} while (1);

#ifdef SIN
	if (!(strlen(ValueForKey(mapent, "origin")))  && ((num_entities-1) != 0))
		{
		mapbrush_t     *brush;
		vec3_t		    origin;
		char		    string[32];
		vec3_t          mins, maxs;
		int			    start, end;
		// Calculate bounds

		start = mapent->firstbrush;
		end = start + mapent->numbrushes;
		ClearBounds (mins, maxs);

		for (j=start ; j<end ; j++)
			{
			brush = &mapbrushes[j];
			if (!brush->numsides)
				continue;	// not a real brush (origin brush) - shouldn't happen
			AddPointToBounds (brush->mins, mins, maxs);
			AddPointToBounds (brush->maxs, mins, maxs);
			}

		// Set the origin to be the centroid of the entity.
		VectorAdd ( mins, maxs, origin);
		VectorScale( origin, 0.5f, origin );

		sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
		SetKeyValue ( mapent, "origin", string);
//        qprintf("Setting origin to %s\n",string);
		}
#endif

	GetVectorForKey (mapent, "origin", mapent->origin);

#ifdef SIN
	if (
		 (!strcmp ("func_areaportal", ValueForKey (mapent, "classname"))) ||
		 (!strcmp ("func_group", ValueForKey (mapent, "classname"))) ||
		(!strcmp ("detail", ValueForKey (mapent, "classname")) && !entitydetails)
	  )
	  {
	  VectorClear( mapent->origin );
	  }
#endif

	//
	// if there was an origin brush, offset all of the planes and texinfo
	//
	if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
	{
		for (i=0 ; i<mapent->numbrushes ; i++)
		{
			b = &mapbrushes[mapent->firstbrush + i];
			for (j=0 ; j<b->numsides ; j++)
			{
				s = &b->original_sides[j];
				newdist = mapplanes[s->planenum].dist -
					DotProduct (mapplanes[s->planenum].normal, mapent->origin);
				s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist, 0, NULL);
#ifdef SIN
				s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
					&side_brushtextures[s-brushsides], mapent->origin, &side_newrefs[s-brushsides]);
			//
			// save off lightinfo
			//
			s->lightinfo = LightinfoForBrushTexture (	&side_brushtextures[s-brushsides] );
#else
				s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
					&side_brushtextures[s-brushsides], mapent->origin);
#endif
			}
			MakeBrushWindings (b);
		}
	}

	// group entities are just for editor convenience
	// toss all brushes into the world entity
	if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
	{
		MoveBrushesToWorld (mapent);
		mapent->numbrushes = 0;
		mapent->wasdetail = true;
	  FreeValueKeys( mapent );
		return true;
	}
#ifdef SIN
	// detail entities are just for editor convenience
	// toss all brushes into the world entity as detail brushes
	if (!strcmp ("detail", ValueForKey (mapent, "classname")) && !entitydetails)
	{
		for (i=0 ; i<mapent->numbrushes ; i++)
		{
		 int j;
		 side_t * s;
			b = &mapbrushes[mapent->firstbrush + i];
	   if (nodetail)
			{
			b->numsides = 0;
			continue;
			}
		 if (!fulldetail)
			{
		  // set the contents for the entire brush
			 b->contents |= CONTENTS_DETAIL;
			   // set the contents in the sides as well
			   for (j=0, s=b->original_sides ; j<b->numsides ; j++,s++)
			   {
			   s->contents |= CONTENTS_DETAIL;
			}
			}
		 else
			{
		  // set the contents for the entire brush
			 b->contents |= CONTENTS_SOLID;
			   // set the contents in the sides as well
			   for (j=0, s=b->original_sides ; j<b->numsides ; j++,s++)
			   {
			   s->contents |= CONTENTS_SOLID;
			}
			}
		}
		MoveBrushesToWorld (mapent);
		mapent->wasdetail = true;
	  FreeValueKeys( mapent );
	  // kill off the entity
	// num_entities--;
		return true;
	}
#endif

	// areaportal entities move their brushes, but don't eliminate
	// the entity
	if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
	{
		char	str[128];

		if (mapent->numbrushes != 1)
			Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1);

		b = &mapbrushes[nummapbrushes-1];
		b->contents = CONTENTS_AREAPORTAL;
		c_areaportals++;
		mapent->areaportalnum = c_areaportals;
		// set the portal number as "style"
		sprintf (str, "%i", c_areaportals);
		SetKeyValue (mapent, "style", str);
		MoveBrushesToWorld (mapent);
		return true;
	}

	return true;
} //end of the function Sin_ParseMapEntity */

//===================================================================

/*
================
LoadMapFile
================
* /
void Sin_LoadMapFile (char *filename)
{
	int		i;
#ifdef SIN
   int num_detailsides=0;
   int num_detailbrushes=0;
   int num_worldsides=0;
   int num_worldbrushes=0;
   int      j,k;
#endif

	qprintf ("--- LoadMapFile ---\n");

	LoadScriptFile (filename);

	nummapbrushsides = 0;
	num_entities = 0;

	while (ParseMapEntity ())
	{
	}

	ClearBounds (map_mins, map_maxs);
	for (i=0 ; i<entities[0].numbrushes ; i++)
	{
		if (mapbrushes[i].mins[0] > 4096)
			continue;	// no valid points
		AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
		AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
	}
#ifdef SIN
   for (j=0;  j<num_entities; j++)
	  {
	   for (i=0 ; i<entities[j].numbrushes ; i++)
		  {
		 side_t * s;
		 mapbrush_t *b;
			b = &mapbrushes[entities[j].firstbrush + i];
		 if (b->numsides && b->contents & CONTENTS_DETAIL)
			num_detailbrushes++;
		 else if (b->numsides)
			num_worldbrushes++;
			for (k=0, s=b->original_sides ; k<b->numsides ; k++,s++)
			   {
			if (s->contents & CONTENTS_DETAIL)
			   num_detailsides++;
			else
			   num_worldsides++;
			   }
	   }
	  }
#endif

	qprintf ("%5i brushes\n", nummapbrushes);
	qprintf ("%5i clipbrushes\n", c_clipbrushes);
	qprintf ("%5i total sides\n", nummapbrushsides);
	qprintf ("%5i boxbevels\n", c_boxbevels);
	qprintf ("%5i edgebevels\n", c_edgebevels);
	qprintf ("%5i entities\n", num_entities);
	qprintf ("%5i planes\n", nummapplanes);
	qprintf ("%5i areaportals\n", c_areaportals);
	qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2],
		map_maxs[0],map_maxs[1],map_maxs[2]);
#ifdef SIN
	qprintf ("%5i detailbrushes\n", num_detailbrushes);
	qprintf ("%5i worldbrushes\n", num_worldbrushes);
	qprintf ("%5i detailsides\n", num_detailsides);
	qprintf ("%5i worldsides\n", num_worldsides);
#endif

} //end of the function Sin_LoadMap */


#ifdef ME       //Begin MAP loading from BSP file
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void Sin_CreateMapTexinfo( void ) {
	int i;
	vec_t defaultvec[4] = {1, 0, 0, 0};

	memcpy( map_texinfo[0].vecs[0], defaultvec, sizeof( defaultvec ) );
	memcpy( map_texinfo[0].vecs[1], defaultvec, sizeof( defaultvec ) );
	map_texinfo[0].flags = 0;
	map_texinfo[0].value = 0;
	strcpy( map_texinfo[0].texture, "generic/misc/red" );  //no texture
	map_texinfo[0].nexttexinfo = -1;
	for ( i = 1; i < sin_numtexinfo; i++ )
	{
		memcpy( map_texinfo[i].vecs, sin_texinfo[i].vecs, sizeof( float ) * 2 * 4 );
		map_texinfo[i].flags = sin_texinfo[i].flags;
		map_texinfo[i].value = 0;
		strcpy( map_texinfo[i].texture, sin_texinfo[i].texture );
		map_texinfo[i].nexttexinfo = -1;
	} //end for
} //end of the function Sin_CreateMapTexinfo
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void Sin_SetLeafBrushesModelNumbers( int leafnum, int modelnum ) {
	int i, brushnum;
	sin_dleaf_t *leaf;

	leaf = &sin_dleafs[leafnum];
	for ( i = 0; i < leaf->numleafbrushes; i++ )
	{
		brushnum = sin_dleafbrushes[leaf->firstleafbrush + i];
		brushmodelnumbers[brushnum] = modelnum;
		dbrushleafnums[brushnum] = leafnum;
	} //end for
} //end of the function Sin_SetLeafBrushesModelNumbers
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void Sin_InitNodeStack( void ) {
	nodestackptr = nodestack;
	nodestacksize = 0;
} //end of the function Sin_InitNodeStack
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void Sin_PushNodeStack( int num ) {
	*nodestackptr = num;
	nodestackptr++;
	nodestacksize++;
	//
	if ( nodestackptr >= &nodestack[NODESTACKSIZE] ) {
		Error( "Sin_PushNodeStack: stack overflow\n" );
	} //end if
} //end of the function Sin_PushNodeStack
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
int Sin_PopNodeStack( void ) {
	//if the stack is empty
	if ( nodestackptr <= nodestack ) {
		return -1;
	}
	//decrease stack pointer
	nodestackptr--;
	nodestacksize--;
	//return the top value from the stack
	return *nodestackptr;
} //end of the function Sin_PopNodeStack
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void Sin_SetBrushModelNumbers( entity_t *mapent ) {
	int n, pn;
	int leafnum;

	//
	Sin_InitNodeStack();
	//head node (root) of the bsp tree
	n = sin_dmodels[mapent->modelnum].headnode;
	pn = 0;

	do
	{
		//if we are in a leaf (negative node number)
		if ( n < 0 ) {
			//number of the leaf
			leafnum = ( -n ) - 1;
			//set the brush numbers
			Sin_SetLeafBrushesModelNumbers( leafnum, mapent->modelnum );
			//walk back into the tree to find a second child to continue with
			for ( pn = Sin_PopNodeStack(); pn >= 0; n = pn, pn = Sin_PopNodeStack() )
			{
				//if we took the first child at the parent node
				if ( sin_dnodes[pn].children[0] == n ) {
					break;
				}
			} //end for
			  //if the stack wasn't empty (if not processed whole tree)
			if ( pn >= 0 ) {
				//push the parent node again
				Sin_PushNodeStack( pn );
				//we proceed with the second child of the parent node
				n = sin_dnodes[pn].children[1];
			} //end if
		} //end if
		else
		{
			//push the current node onto the stack
			Sin_PushNodeStack( n );
			//walk forward into the tree to the first child
			n = sin_dnodes[n].children[0];
		} //end else
	} while ( pn >= 0 );
} //end of the function Sin_SetBrushModelNumbers
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void Sin_BSPBrushToMapBrush( sin_dbrush_t *bspbrush, entity_t *mapent ) {
	mapbrush_t *b;
	int i, k, n;
	side_t *side, *s2;
	int planenum;
	sin_dbrushside_t *bspbrushside;
	sin_dplane_t *bspplane;

	if ( nummapbrushes >= MAX_MAPFILE_BRUSHES ) {
		Error( "nummapbrushes >= MAX_MAPFILE_BRUSHES" );
	}

	b = &mapbrushes[nummapbrushes];
	b->original_sides = &brushsides[nummapbrushsides];
	b->entitynum = mapent - entities;
	b->brushnum = nummapbrushes - mapent->firstbrush;
	b->leafnum = dbrushleafnums[bspbrush - sin_dbrushes];

	for ( n = 0; n < bspbrush->numsides; n++ )
	{
		//pointer to the bsp brush side
		bspbrushside = &sin_dbrushsides[bspbrush->firstside + n];

		if ( nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES ) {
			Error( "MAX_MAPFILE_BRUSHSIDES" );
		} //end if
		  //pointer to the map brush side
		side = &brushsides[nummapbrushsides];
		//if the BSP brush side is textured
		if ( sin_dbrushsidetextured[bspbrush->firstside + n] ) {
			side->flags |= SFL_TEXTURED;
		} else { side->flags &= ~SFL_TEXTURED;}
		//ME: can get side contents and surf directly from BSP file
		side->contents = bspbrush->contents;
		//if the texinfo is TEXINFO_NODE
		if ( bspbrushside->texinfo < 0 ) {
			side->surf = 0;
		} else { side->surf = sin_texinfo[bspbrushside->texinfo].flags;}

		// translucent objects are automatically classified as detail
//		if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
//			side->contents |= CONTENTS_DETAIL;
		if ( side->contents & ( CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP ) ) {
			side->contents |= CONTENTS_DETAIL;
		}
		if ( fulldetail ) {
			side->contents &= ~CONTENTS_DETAIL;
		}
		if ( !( side->contents & ( ( LAST_VISIBLE_CONTENTS - 1 )
								   | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP | CONTENTS_MIST )  ) ) {
			side->contents |= CONTENTS_SOLID;
		}

		// hints and skips are never detail, and have no content
		if ( side->surf & ( SURF_HINT | SURF_SKIP ) ) {
			side->contents = 0;
			side->surf &= ~CONTENTS_DETAIL;
		}

		//ME: get a plane for this side
		bspplane = &sin_dplanes[bspbrushside->planenum];
		planenum = FindFloatPlane( bspplane->normal, bspplane->dist, 0, NULL );
		//
		// see if the plane has been used already
		//
		//ME: this really shouldn't happen!!!
		//ME: otherwise the bsp file is corrupted??
		//ME: still it seems to happen, maybe Johny Boy's
		//ME: brush bevel adding is crappy ?
		for ( k = 0; k < b->numsides; k++ )
		{
			s2 = b->original_sides + k;
			if ( s2->planenum == planenum ) {
				Log_Print( "Entity %i, Brush %i: duplicate plane\n"
						   , b->entitynum, b->brushnum );
				break;
			}
			if ( s2->planenum == ( planenum ^ 1 ) ) {
				Log_Print( "Entity %i, Brush %i: mirrored plane\n"
						   , b->entitynum, b->brushnum );
				break;
			}
		}
		if ( k != b->numsides ) {
			continue;       // duplicated

		}
		//
		// keep this side
		//
		//ME: reset pointer to side, why? hell I dunno (pointer is set above already)
		side = b->original_sides + b->numsides;
		//ME: store the plane number
		side->planenum = planenum;
		//ME: texinfo is already stored when bsp is loaded
		//NOTE: check for TEXINFO_NODE, otherwise crash in Sin_BrushContents
		if ( bspbrushside->texinfo < 0 ) {
			side->texinfo = 0;
		} else { side->texinfo = bspbrushside->texinfo;}

		// save the td off in case there is an origin brush and we
		// have to recalculate the texinfo
		// ME: don't need to recalculate because it's already done
		//     (for non-world entities) in the BSP file
//		side_brushtextures[nummapbrushsides] = td;

		nummapbrushsides++;
		b->numsides++;
	} //end for

	// get the content for the entire brush
	b->contents = bspbrush->contents;
	Sin_BrushContents( b );

	if ( BrushExists( b ) ) {
		c_squattbrushes++;
		b->numsides = 0;
		return;
	} //end if

	//if we're creating AAS
	if ( create_aas ) {
		//create the AAS brushes from this brush, don't add brush bevels
		AAS_CreateMapBrushes( b, mapent, false );
		return;
	} //end if

	// allow detail brushes to be removed
	if ( nodetail && ( b->contents & CONTENTS_DETAIL ) ) {
		b->numsides = 0;
		return;
	} //end if

	// allow water brushes to be removed
	if ( nowater && ( b->contents & ( CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER ) ) ) {
		b->numsides = 0;
		return;
	} //end if

	// create windings for sides and bounds for brush
	MakeBrushWindings( b );

	//mark brushes without winding or with a tiny window as bevels
	MarkBrushBevels( b );

	// brushes that will not be visible at all will never be
	// used as bsp splitters
	if ( b->contents & ( CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP ) ) {
		c_clipbrushes++;
		for ( i = 0; i < b->numsides; i++ )
			b->original_sides[i].texinfo = TEXINFO_NODE;
	} //end for

	//
	// origin brushes are removed, but they set
	// the rotation origin for the rest of the brushes
	// in the entity.  After the entire entity is parsed,
	// the planenums and texinfos will be adjusted for
	// the origin brush
	//
	//ME: not needed because the entities in the BSP file already
	//    have an origin set
//	if (b->contents & CONTENTS_ORIGIN)
//	{
//		char	string[32];
//		vec3_t	origin;
//
//		if (num_entities == 1)
//		{
//			Error ("Entity %i, Brush %i: origin brushes not allowed in world"
//				, b->entitynum, b->brushnum);
//			return;
//		}
//
//		VectorAdd (b->mins, b->maxs, origin);
//		VectorScale (origin, 0.5, origin);
//
//		sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
//		SetKeyValue (&entities[b->entitynum], "origin", string);
//
//		VectorCopy (origin, entities[b->entitynum].origin);
//
//		// don't keep this brush
//		b->numsides = 0;
//
//		return;
//	}

	//ME: the bsp brushes already have bevels, so we won't try to
	//    add them again (especially since Johny Boy's bevel adding might
	//    be crappy)
//	AddBrushBevels(b);

	nummapbrushes++;
	mapent->numbrushes++;
} //end of the function Sin_BSPBrushToMapBrush
//===========================================================================
//===========================================================================
void Sin_ParseBSPBrushes( entity_t *mapent ) {
	int i, testnum = 0;

	//give all the brushes that belong to this entity the number of the
	//BSP model used by this entity
	Sin_SetBrushModelNumbers( mapent );
	//now parse all the brushes with the correct mapent->modelnum
	for ( i = 0; i < sin_numbrushes; i++ )
	{
		if ( brushmodelnumbers[i] == mapent->modelnum ) {
			testnum++;
			Sin_BSPBrushToMapBrush( &sin_dbrushes[i], mapent );
		} //end if
	} //end for
} //end of the function Sin_ParseBSPBrushes
//===========================================================================
//===========================================================================
qboolean Sin_ParseBSPEntity( int entnum ) {
	entity_t    *mapent;
	char *model;
	int startbrush, startsides;

	startbrush = nummapbrushes;
	startsides = nummapbrushsides;

	mapent = &entities[entnum]; //num_entities];
	mapent->firstbrush = nummapbrushes;
	mapent->numbrushes = 0;
	mapent->modelnum = -1;  //-1 = no model

	model = ValueForKey( mapent, "model" );
	if ( model && *model == '*' ) {
		mapent->modelnum = atoi( &model[1] );
		//Log_Print("model = %s\n", model);
		//Log_Print("mapent->modelnum = %d\n", mapent->modelnum);
	} //end if

	GetVectorForKey( mapent, "origin", mapent->origin );

	//if this is the world entity it has model number zero
	//the world entity has no model key
	if ( !strcmp( "worldspawn", ValueForKey( mapent, "classname" ) ) ) {
		mapent->modelnum = 0;
	} //end if
	  //if the map entity has a BSP model (a modelnum of -1 is used for
	  //entities that aren't using a BSP model)
	if ( mapent->modelnum >= 0 ) {
		//parse the bsp brushes
		Sin_ParseBSPBrushes( mapent );
	} //end if
	  //
	  //the origin of the entity is already taken into account
	  //
	  //func_group entities can't be in the bsp file
	  //
	  //check out the func_areaportal entities
	if ( !strcmp( "func_areaportal", ValueForKey( mapent, "classname" ) ) ) {
		c_areaportals++;
		mapent->areaportalnum = c_areaportals;
		return true;
	} //end if
	return true;
} //end of the function Sin_ParseBSPEntity
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void Sin_LoadMapFromBSP( char *filename, int offset, int length ) {
	int i;

	Log_Print( "-- Sin_LoadMapFromBSP --\n" );
	//loaded map type
	loadedmaptype = MAPTYPE_SIN;

	Log_Print( "Loading map from %s...\n", filename );
	//load the bsp file
	Sin_LoadBSPFile( filename, offset, length );

	//create an index from bsp planes to map planes
	//DPlanes2MapPlanes();
	//clear brush model numbers
	for ( i = 0; i < MAX_MAPFILE_BRUSHES; i++ )
		brushmodelnumbers[i] = -1;

	nummapbrushsides = 0;
	num_entities = 0;

	Sin_ParseEntities();
	//
	for ( i = 0; i < num_entities; i++ )
	{
		Sin_ParseBSPEntity( i );
	} //end for

	//get the map mins and maxs from the world model
	ClearBounds( map_mins, map_maxs );
	for ( i = 0; i < entities[0].numbrushes; i++ )
	{
		if ( mapbrushes[i].mins[0] > 4096 ) {
			continue;   //no valid points
		}
		AddPointToBounds( mapbrushes[i].mins, map_mins, map_maxs );
		AddPointToBounds( mapbrushes[i].maxs, map_mins, map_maxs );
	} //end for
	  //
	Sin_CreateMapTexinfo();
} //end of the function Sin_LoadMapFromBSP

void Sin_ResetMapLoading( void ) {
	//reset for map loading from bsp
	memset( nodestack, 0, NODESTACKSIZE * sizeof( int ) );
	nodestackptr = NULL;
	nodestacksize = 0;
	memset( brushmodelnumbers, 0, MAX_MAPFILE_BRUSHES * sizeof( int ) );
} //end of the function Sin_ResetMapLoading

//End MAP loading from BSP file

#endif //ME
